package com.sakila.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.sakila.dao.InventoryDao;
import com.sakila.dao.PaymentDao;
import com.sakila.dao.RentalDao;
import com.sakila.pojo.Film;
import com.sakila.pojo.Inventory;
import com.sakila.pojo.Member;
import com.sakila.pojo.Payment;
import com.sakila.pojo.Rental;
import com.sakila.pojo.Staff;
import com.sakila.pojo.Store;
import com.sakila.service.RentalService;
import com.sakila.vo.BarChartVo;

@Service
public class RentalServiceImpl implements RentalService {
	@Resource
	private InventoryDao inventoryDao;
	@Resource
	private RentalDao rentalDao;
	@Resource
	private PaymentDao paymentDao;
	
	@Override
	public int addRental(Integer[] filmIds, Staff staff, Integer memberId, List<Payment> payments) {
		List<Integer> idList = new ArrayList<Integer>();
		/*for (Integer filmId : filmIds) {
			if(filmId == null) continue;
			idList.add(filmId);
		}*/
		
		Arrays.stream(filmIds).filter(id -> id != null).forEach(id -> idList.add(id));
		
		for (Integer id : idList) {
			if(checkRentalable(id, staff.getStore().getId()) == false){
				return id;
			}
		}
		
		Member member = new Member();
		member.setId(memberId);
		idList.forEach(id -> {
			Film film = new Film();
			film.setId(id);
			
			Inventory inventory = inventoryDao.findByFilmAndStore(film, staff.getStore()).get(0);
			Rental rental = new Rental();
			rental.setCustomer(member);
			rental.setRentalDate(new Date());
			rental.setStaff(staff);
			rental.setInventory(inventory);
			rentalDao.save(rental);
			
			film = inventory.getFilm();
			Payment payment = new Payment();
			payment.setCustomer(member);
			payment.setPaymentDate(new Date());
			payment.setRental(rental);
			payment.setStaff(staff);
			payment.setAmount(film.getRentalRate());
			paymentDao.save(payment);
			payments.add(payment);
		});
		return 0;
	}
	
	private boolean checkRentalable(Integer filmId, Integer storeId) {
		Film film = new Film();
		film.setId(filmId);
		Store store = new Store();
		store.setId(storeId);
		
		if(inventoryDao.findByFilmAndStore(film, store).size() > 0){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public boolean isCustomerRentable(Member member) {
		Long count = paymentDao.getTotalNumOfRowsByUnreturned(member);
		return count < 3L ? true : false;
	}

	@Override
	public List<BarChartVo> getTop5HotCategories() {
		Map<Object, Map<String, Object>> map = rentalDao.getTop5HotCategories();
		List<BarChartVo> list = new ArrayList<BarChartVo>();		
		map.forEach((k,v) -> 
						list.add(new BarChartVo((Long)v.get("counts"), v.get("name").toString()))
					);
		return createBarChartVoList(list);
	}

	@Override
	public List<BarChartVo> getTop10HotFilms() {
		Map<Object, Map<String, Object>> map = rentalDao.getTop10HotFilms();
		List<BarChartVo> list = new ArrayList<BarChartVo>();		
		map.forEach((k,v) -> 
						list.add(new BarChartVo((Long)v.get("counts"), v.get("title").toString()))
					);
		return createBarChartVoList(list);
	}
	
	private List<BarChartVo> createBarChartVoList(List<BarChartVo> list){
		//descending sort
		list.sort((BarChartVo o1, BarChartVo o2) -> -o1.getYaxis().compareTo(o2.getYaxis()));
		for (int i = 0; i < list.size(); i++) {
			list.get(i).setLabel("No." + (i + 1));
		}
		
		//JfreeChart need ascending sort to show descending value
		Collections.reverse(list);
		return list;
	}
	
	private Double getPercentWithTwoDecimals(Object num1, Object num2){
		DecimalFormat df = new DecimalFormat("#.##");
		
		//final pattern**.**
		double value = new Double(num1.toString()) / new Double(num2.toString()) * 100; 
		return new Double(df.format(value));
	}
}
